package com.cee.auditlog.process.impl;

import com.cee.auditlog.bean.AuditLog;
import com.cee.auditlog.process.AuditLogProcess;
import com.cee.dao.AuditLogMapper;
import com.cee.dto.AuditLogDTO;
import com.cee.enums.AuditLogAction;
import com.cee.util.AuthContextHolder;
import com.cee.util.JsonUtil;
import com.cee.util.SystemUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.mapping.SqlCommandType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

@Transactional
@Service
public class AuditLogProcessImpl implements AuditLogProcess {

    private final static Logger logger = LoggerFactory.getLogger(AuditLogProcessImpl.class);

    @Autowired
    private AuditLogMapper auditLogMapper;
    
/*    @Autowired
    private AuditLogDetailMapper auditLogDetailMapper;*/

    @Override
    public void process(String tableName, String sqlCommandType, Map<String, List<AuditLog>> columnLogsOfRow) {

        if (StringUtils.isEmpty(tableName)) {
            logger.warn("Skip empty tableName");
        }

        if (!(SqlCommandType.INSERT.toString().equals(sqlCommandType) || SqlCommandType.UPDATE.toString().equals(sqlCommandType))) {
            logger.warn("Skip the sqlCommandType '{}'", sqlCommandType);
        }

        if (CollectionUtils.isEmpty(columnLogsOfRow.keySet())) {
            logger.warn("Skip empty columnLogsOfRow");
        }

        if (SqlCommandType.INSERT.toString().equals(sqlCommandType)) {

            for (Entry<String, List<AuditLog>> entry : columnLogsOfRow.entrySet()) {
                List<AuditLog> auditLogList = entry.getValue();
                String rowId = auditLogList.get(0).getRowId();

                AuditLogDTO auditLogDTO = new AuditLogDTO();
                auditLogDTO.setDbName("");
                auditLogDTO.setTableName(tableName);
                auditLogDTO.setActionCode(AuditLogAction.INSERT.getCode());
                auditLogDTO.setRowId(rowId != null ? StringUtils.trimToNull(rowId.toString()) : "");

                Map<String, String> newValueMap = new HashMap<>();
                for (AuditLog auditLog : auditLogList) {
                    newValueMap.put(auditLog.getColumnName(), auditLog.getNewValue());
                }

                auditLogDTO.setOldValue("{}");
                auditLogDTO.setNewValue(JsonUtil.format(newValueMap));

                addAuditLog(auditLogDTO);
            }
        }
        if (SqlCommandType.UPDATE.toString().equals(sqlCommandType)) {
            for (Entry<String, List<AuditLog>> entry : columnLogsOfRow.entrySet()) {
                String rowId = entry.getKey();
                List<AuditLog> auditLogList = entry.getValue();
                
                AuditLogDTO auditLogDTO = new AuditLogDTO();
                auditLogDTO.setDbName(SystemUtil.DB_NAME);
                auditLogDTO.setTableName(tableName);
                auditLogDTO.setActionCode(AuditLogAction.UPDATE.getCode());
                auditLogDTO.setRowId(rowId != null ? StringUtils.trimToNull(rowId.toString()) : null);

                Map<String, String> oldValueMap = new HashMap<>();
                Map<String, String> newValueMap = new HashMap<>();

                for (AuditLog auditLog : auditLogList) {
                    oldValueMap.put(auditLog.getColumnName(), auditLog.getOldValue());
                    newValueMap.put(auditLog.getColumnName(), auditLog.getNewValue());
                }

                auditLogDTO.setOldValue(JsonUtil.format(oldValueMap));
                auditLogDTO.setNewValue(JsonUtil.format(newValueMap));

                addAuditLog(auditLogDTO);
            }
        }
    }
    
    public void addAuditLog(AuditLogDTO auditLogDTO) {
        logger.info("ready to add audit log");

        String userId = AuthContextHolder.getUserId()== null?"CEE Test":AuthContextHolder.getUserId()+"";
        auditLogDTO.setLastRecTxnDate(new Date());
        auditLogDTO.setLastRecTxnUserId(userId);
        auditLogDTO.setLastRecTxnTypeCode("I");
        auditLogMapper.insert(auditLogDTO);
    }

}
